package com.matrix.order.infrastructure.gateway.acl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.matrix.api.im.ImApi;
import com.matrix.api.im.dto.SystemMessageDTO;
import com.matrix.order.domain.model.OrderItem;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础设施层: IM服务防腐层(Anti-Corruption Layer)
 * 职责:
 *  - 封装对 IM 微服务的调用(通过 Feign Client)。
 *  - 将外部上下文(IM服务)的DTO转换为领域内的通知请求。
 *  - 隔离领域层与外部服务的直接依赖。
 * </p>
 *
 * @author 有点甜
 * @since 2025/8/2
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ImAcl {

    @DubboReference(check = false, retries = 0)
    private ImApi imApi;
    private final ObjectMapper objectMapper;

    public void sendNewOrderNotification(Long ownerId, String areaSeat, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(ownerId);
            message.setTitle("您有新的订单");
            message.setContent(String.format("桌号 %s 已下单,请及时处理！", areaSeat));
            message.setType("NEW_ORDER");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送新订单通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        } catch (Exception e) {
            log.error("发送新订单通知时发生未知异常, orderId: {}", orderId, e);
        }
    }

    public void sendOrderAcceptedNotification(Long userId, String orderNo, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("商家已接单");
            message.setContent(String.format("您的订单[%s]商家已接单,正在火速备餐中！", orderNo));
            message.setType("ORDER_ACCEPTED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送订单接单通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }

    public void sendOrderRejectedNotification(Long userId, String orderNo, String reason, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("订单已取消");
            String finalReason = StringUtils.hasText(reason) ? reason : "商家系统原因";
            message.setContent(String.format("非常抱歉,您的订单[%s]因“%s”被商家取消,支付金额将原路退回。", orderNo, finalReason));
            message.setType("ORDER_REJECTED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送订单拒绝通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }

    public void sendCancelDishRequestNotification(Long ownerId, String areaSeat, List<OrderItem> canceledItems, String reason, Long orderId) {
        try {
            String itemsName = canceledItems.stream()
                    .map(OrderItem::getProductName)
                    .collect(Collectors.joining("、"));
            String finalReason = StringUtils.hasText(reason) ? reason : "无";

            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(ownerId);
            message.setTitle("退菜申请");
            message.setContent(String.format("桌号 %s 的顾客申请退菜：%s (共%d项)。原因：%s",
                    areaSeat, itemsName, canceledItems.size(), finalReason));
            message.setType("CANCEL_DISH_REQUEST");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送退菜申请通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }

    public void sendCancelDishApprovedNotification(Long userId, String productName, BigDecimal refundAmount, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("退菜成功");
            message.setContent(String.format("您订单中的菜品 [%s] 已成功退菜,退款 %.2f 元将原路返回。", productName, refundAmount));
            message.setType("DISH_CANCEL_APPROVED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送同意退菜通知失败, userId: {}, RPC异常: {}", userId, e.getMessage());
        }
    }

    public void sendCancelDishRejectedNotification(Long userId, String productName, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("退菜申请被拒绝");
            message.setContent(String.format("抱歉,您订单中的菜品 [%s] 的退菜申请已被商家拒绝,如有疑问请联系商家。", productName));
            message.setType("DISH_CANCEL_REJECTED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送拒绝退菜通知失败, userId: {}, RPC异常: {}", userId, e.getMessage());
        }
    }

    public void sendWaiterCallNotification(Long ownerId, String areaSeat, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(ownerId);
            message.setTitle("服务呼叫");
            message.setContent(String.format("桌号 %s 正在呼叫服务！", areaSeat));
            message.setType("CALL_WAITER");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送呼叫服务员通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }

    public void sendOrderCreationResult(Long userId, Map<String, Object> payload) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("订单状态更新");
            message.setContent(objectMapper.writeValueAsString(payload));
            message.setType("ORDER_STATUS_UPDATE");
            message.setRelatedId((String) payload.get("orderNo"));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("推送订单创建结果失败, userId: {}, RPC异常: {}", userId, e.getMessage());
        } catch (Exception e) {
            log.error("推送订单创建结果时发生序列化异常, userId: {}", userId, e);
        }
    }

    public void sendProductionCompletedNotification(Long userId, String orderNo, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("餐品制作完成");
            message.setContent(String.format("您的订单[%s]餐品已制作完成，准备上菜啦！", orderNo));
            message.setType("ORDER_PRODUCTION_COMPLETED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送餐品制作完成通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }

    public void sendServingCompletedNotification(Long userId, String orderNo, Long orderId) {
        try {
            SystemMessageDTO message = new SystemMessageDTO();
            message.setUserId(userId);
            message.setTitle("餐品已上齐");
            message.setContent(String.format("您的订单[%s]餐品已全部上齐，祝您用餐愉快！", orderNo));
            message.setType("ORDER_SERVING_COMPLETED");
            message.setRelatedId(String.valueOf(orderId));
            imApi.sendSystemMessage(message);
        } catch (RpcException e) {
            log.error("发送上菜完成通知失败, orderId: {}, RPC异常: {}", orderId, e.getMessage());
        }
    }
}